﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Security.Permissions;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using Microsoft.VisualBasic;

namespace KABS_Commander
{
    public partial class KABS_Commander : Form
    {
        // Serial initialization
        private List<string> getValidSerialPorts()
        {
            List<string> result = new List<string>();
            // use registry info to get com info
            RegistryKey hklm = Registry.LocalMachine;
            RegistryKey hs = hklm.OpenSubKey(@"HARDWARE\DEVICEMAP\SERIALCOMM");
            for (int i = 0; i < hs.ValueCount; i++)
            {
                result.Add(hs.GetValue(hs.GetValueNames()[i]).ToString());
            }
            hklm.Close();
            return result;
        }

        private bool compareList(ref List<string> ls1, ref List<string> ls2)
        {
            if (ls1.Count != ls2.Count)
                return false;
            for (int i = 0; i < ls1.Count; i++)
            {
                if (!ls1.Contains(ls2[i]) || !ls2.Contains(ls1[i]))
                {
                    return false;
                }
            }

            return true;
        }

        private bool addPortNames()
        {
            List<string> serialPorts = getValidSerialPorts();
            List<string> oldPorts = new List<string>();

            if (serialPorts.Count == 0)
            {
                comboBox_serialName.Items.Clear();
                //MessageBox.Show("No valid serial port found!");
                return false;
            }

            foreach (string s in comboBox_serialName.Items.Cast<string>())
            {
                oldPorts.Add(s);
            }

            if (false == compareList(ref serialPorts, ref oldPorts))
            {
                comboBox_serialName.Items.Clear();

                foreach (string s in serialPorts)
                {
                    comboBox_serialName.Items.Add(s);
                }
            }
            return true;
        }

        private void InitializeSerial()
        {
            bool isValidPortAvailable = addPortNames();

            if (isValidPortAvailable == false)
                button_toggleserial.Enabled = false;
            else
                button_toggleserial.Enabled = true;

            if (comboBox_serialName.Items.Count == 1)
                comboBox_serialName.SelectedIndex = 0;
            if (-1 == comboBox_serialBaudRate.SelectedIndex)
                comboBox_serialBaudRate.SelectedIndex = 4;
            if (-1 == comboBox_serialDataBits.SelectedIndex)
                comboBox_serialDataBits.SelectedIndex = 3;
            if (-1 == comboBox_serialParity.SelectedIndex)
                comboBox_serialParity.SelectedIndex = 0;
            if (-1 == comboBox_serialStopBits.SelectedIndex)
                comboBox_serialStopBits.SelectedIndex = 0;
            if (-1 == comboBox_serialFlowctrl.SelectedIndex)
                comboBox_serialFlowctrl.SelectedIndex = 0;

            setSerialSettingEnable();

        }

        private Parity getSerialParity()
        {
            int idx = comboBox_serialParity.SelectedIndex;

            switch (idx)
            {
                case 0:
                    return System.IO.Ports.Parity.None;
                case 1:
                    return System.IO.Ports.Parity.Odd;
                case 2:
                    return System.IO.Ports.Parity.Even;
                case 3:
                    return System.IO.Ports.Parity.Mark;
                case 4:
                    return System.IO.Ports.Parity.Space;
                default:
                    return System.IO.Ports.Parity.None;
            }
        }

        private StopBits getSerialStopBits()
        {
            int idx = comboBox_serialStopBits.SelectedIndex;

            switch (idx)
            {
                case 0:
                    return System.IO.Ports.StopBits.One;
                case 1:
                    return System.IO.Ports.StopBits.OnePointFive;
                case 2:
                    return System.IO.Ports.StopBits.Two;
                default:
                    return System.IO.Ports.StopBits.One;
            }
        }

        private Handshake getSerialHandshake()
        {
            int idx = comboBox_serialFlowctrl.SelectedIndex;

            switch (idx)
            {
                case 0:
                    return System.IO.Ports.Handshake.None;
                case 1:
                    return System.IO.Ports.Handshake.XOnXOff;
                case 2:
                    return System.IO.Ports.Handshake.RequestToSend;
                case 3:
                    return System.IO.Ports.Handshake.RequestToSendXOnXOff;
                default:
                    return System.IO.Ports.Handshake.None;
            }
        }

        private void setSerialSettingEnable()
        {
            bool b = !serialPort_kabs.IsOpen;

            comboBox_serialName.Enabled = b;
            comboBox_serialBaudRate.Enabled = b;
            comboBox_serialDataBits.Enabled = b;
            comboBox_serialParity.Enabled = b;
            comboBox_serialStopBits.Enabled = b;
            comboBox_serialFlowctrl.Enabled = b;
            SetInputEnable();
        }

        private void toggleSerialState()
        {

            if (!serialPort_kabs.IsOpen)
            {
                button_toggleserial.Text = "Close";
                try
                {
                    serialPort_kabs.PortName = comboBox_serialName.Text;
                    serialPort_kabs.BaudRate = int.Parse(comboBox_serialBaudRate.Text);
                    serialPort_kabs.DataBits = int.Parse(comboBox_serialDataBits.Text);
                    serialPort_kabs.Parity = getSerialParity();
                    serialPort_kabs.StopBits = getSerialStopBits();
                    serialPort_kabs.Handshake = getSerialHandshake();
                    if (serialPort_kabs.IsOpen)
                        serialPort_kabs.Close();
                    serialPort_kabs.Open();
                }
                catch (Exception ee)
                {
                    button_toggleserial.Text = "Open";
                    return;
                }
            }
            else if (serialPort_kabs.IsOpen)
            {
                button_toggleserial.Text = "Open";
                try
                {
                    serialPort_kabs.DiscardInBuffer();
                    serialPort_kabs.DiscardOutBuffer();
                    serialPort_kabs.Dispose();
                    serialPort_kabs.Close();
                }
                catch (Exception ee)
                {
                    return;
                }
            }
            setSerialSettingEnable();
        }

        // Serial open
        private void button_toggleserial_Click(object sender, EventArgs e)
        {
            toggleSerialState();
        }


        private void serialPort_kabs_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;
            StringBuilder sb = new StringBuilder();
            string time = string.Empty;
            string hex = string.Empty;
            if (sp.BytesToRead > 0)
            {
                sb.Append(sp.ReadExisting());
            }

            appendText(time + sb.ToString() + hex);
        }

        // periodly refresh serial ports check
        private void timer_serialCheck_Tick(object sender, EventArgs e)
        {
            if (!serialPort_kabs.IsOpen)
            {
                InitializeSerial();
            }
        }
    }
}